#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
#include <omp.h>
#include <limits.h>

#include <cassert>
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

#include "Timer.h"
#include "ResultDatabase.h"
#include "ParallelResultDatabase.h"
#include "OptionParser.h"
#include "InvalidArgValue.h"

using namespace std;

// Forward Declarations
void addBenchmarkSpecOptions(OptionParser &op);
void RunBenchmark(ResultDatabase &resultDB, OptionParser &op);

int main(int argc, char* argv[])
{
	int mpi_size, mpi_rank;
	MPI_Init(&argc,&argv);
	MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
	MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
	cerr << "MPI Task " << mpi_rank << "/" << mpi_size - 1 << " starting....\n";

    OptionParser op;
	
    //Add shared options to the parser
    op.addOption("passes", OPT_INT, "10", "specify number of passes", 'n');
    op.addOption("size", OPT_INT, "1", "specify problem size", 's');
    op.addOption("quiet", OPT_BOOL, "", "write minimum necessary to standard output", 'q');
    addBenchmarkSpecOptions(op);

    if (!op.parse(argc, argv))
    {
       if (mpi_rank == 0)
           op.usage();
       MPI_Finalize();
       return (op.HelpRequested() ? 0 : 1);
    }

    ResultDatabase resultDB;

    RunBenchmark(resultDB, op);
	
    
    // Dump summary
	ParallelResultDatabase pardb;
	pardb.MergeSerialDatabases(resultDB,MPI_COMM_WORLD);
	if (mpi_rank==0)
	{
		pardb.DumpSummary(cout);
		pardb.DumpOutliers(cout);
	}

	MPI_Finalize();

	return 0;
}

// eof 
